﻿using System;
using System.Xml;

namespace Graphe.Collations
{
    public class Verse : ICollationElement, IComparable<Verse>
    {
        #region Constructor

        public Verse()
        {
            Variants = new VariantCollection();
            Fragments = new FragmentCollection();
            Notes = new NoteCollection();
            LacunateManuscripts = new LacunateManuscriptCollection();
            NominaSacra = new SacrumCollection();
        }

        #endregion
        #region Public Properties

        public string VersificationMarking { get; set; }
        public string Text { get; set; }
        public VariantCollection Variants { get; set; }
        public FragmentCollection Fragments { get; set; }
        public NoteCollection Notes { get; set; }
        public LacunateManuscriptCollection LacunateManuscripts { get; set; }
        public SacrumCollection NominaSacra { get; set; }

        #endregion
        #region ICollationElement Members

        public void Parse(XmlReader reader, CollationDebugMessages debugMessages)
        {

            if (reader.MoveToFirstAttribute())
            {
                do
                {
                    if (reader.Name == "Reference")
                    {
                        this.VersificationMarking = reader.ReadContentAsString();
                    }
                    else
                    {
                        debugMessages.Add(String.Format("Attribute '{0}' with value '{1}' is unknown and will not be persisted in the in-memory model. This also means it won't be saved after you change the collation.", reader.Name, reader.ReadContentAsString()));
                    }
                } while (reader.MoveToNextAttribute());
            }


            while (reader.Read())
            {
                while (true)
                {
                    MoveToNextElement(reader);
                    if (reader.Name == "Variants" ||
                        reader.Name == "NominaSacra" ||
                        reader.Name == "Notes" ||
                        reader.Name == "Fragments" ||
                        reader.Name == "Lacuna" ||
                        reader.Name == "Text")
                        break;

                    if (reader.Name == "Verse")
                        return;
                }

                switch (reader.Name)
                {
                    case "Variants":
                        Variants = new VariantCollection();
                        Variants.Parse(reader, debugMessages);
                        break;
                    case "NominaSacra":
                        NominaSacra = new SacrumCollection();
                        NominaSacra.Parse(reader, debugMessages);
                        break;
                    case "Notes":
                        Notes = new NoteCollection();
                        Notes.Parse(reader, debugMessages);
                        break;
                    case "Fragments":
                        Fragments = new FragmentCollection();
                        Fragments.Parse(reader, debugMessages);
                        break;
                    case "Lacuna":
                        LacunateManuscripts = new LacunateManuscriptCollection();
                        LacunateManuscripts.Parse(reader, debugMessages);
                        break;
                    case "Text":
                        reader.Read();
                        Text = reader.ReadContentAsString();
                        break;
                }
            }
        }

        private static void MoveToNextElement(XmlReader subReader)
        {
            if (subReader.Name == String.Empty)
            {
                do
                {
                    subReader.Read();
                } while (subReader.Name == String.Empty);
            }
        }

        public void Render(XmlTextWriter writer)
        {
            writer.WriteStartElement("Verse");
            writer.WriteAttributeString("Reference", this.VersificationMarking);

            {
                writer.WriteStartElement("Text");

                writer.WriteString(Text);
                writer.WriteEndElement();

                if (Variants.Count > 0)
                {
                    writer.WriteStartElement("Variants");

                    foreach (Variant variant in Variants)
                        variant.Render(writer);

                    writer.WriteEndElement();
                }

                if (Fragments.Count > 0)
                {
                    writer.WriteStartElement("Fragments");

                    foreach (Fragment fragment in Fragments)
                        fragment.Render(writer);

                    writer.WriteEndElement();
                }

                if (Notes.Count > 0)
                {
                    writer.WriteStartElement("Notes");

                    foreach (Note note in Notes)
                        note.Render(writer);

                    writer.WriteEndElement();
                }

                if (LacunateManuscripts.Count > 0)
                {
                    writer.WriteStartElement("Lacunate");

                    foreach (Manuscript manuscript in LacunateManuscripts)
                        manuscript.Render(writer);

                    writer.WriteEndElement();
                }

                if (NominaSacra.Count > 0)
                {
                    writer.WriteStartElement("NominaSacra");

                    foreach (Sacrum sacrum in NominaSacra)
                        sacrum.Render(writer);

                    writer.WriteEndElement();
                }
            }
            writer.WriteEndElement();
        }

        #endregion
        #region IComparable<Verse> Members

        public int CompareTo(Verse other)
        {
            if (Text != other.Text || VersificationMarking != other.VersificationMarking)
                return -1;

            if (Variants != null && Variants.CompareTo(other.Variants) == -1)
                return -1;
            else if (NominaSacra != null && NominaSacra.CompareTo(other.NominaSacra) == -1)
                return -1;
            else if (Notes != null && Notes.CompareTo(other.Notes) == -1)
                return -1;
            else if (Fragments != null && Fragments.CompareTo(other.Fragments) == -1)
                return -1;
            else if (LacunateManuscripts != null && LacunateManuscripts.CompareTo(other.LacunateManuscripts) == -1)
                return -1;

            return 0;
        }

        #endregion
    }
}
